home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 40 / Amiga Format CD40 (1999-05-11)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-06].iso / -seriously_amiga- / misc / pdflib / p_font.c < prev    next >
C/C++ Source or Header  |  1999-03-24  |  14KB  |  483 lines

  1. /* p_font.c
  2.  * Copyright (C) 1997-98 Thomas Merz. All rights reserved.
  3.  *
  4.  * PDFlib font embedding routines
  5.  */
  6.  
  7. #include <string.h>
  8.  
  9. #include "p_intern.h"
  10. #include "afmparse.h"
  11. #include "ansi_e.h"
  12. #include "macrom_e.h"
  13. #include "pdfdoc_e.h"
  14.  
  15. #define MAXFILENAME    256
  16. #define LINEBUFLEN    256
  17.  
  18. /* Bit positions for font descriptor flag */
  19. #define FIXEDWIDTH    (long) (1L<<0)
  20. #define SERIF        (long) (1L<<1)
  21. #define SYMBOL        (long) (1L<<2)
  22. #define SCRIPT        (long) (1L<<3)
  23. #define ADOBESTANDARD    (long) (1L<<5)
  24. #define ITALIC        (long) (1L<<6)
  25. #define SMALLCAPS    (long) (1L<<17)
  26. #define FORCEBOLD    (long) (1L<<18)
  27.  
  28. /* dummy values for stem width */
  29. #define DEFAULT_STEMWIDTH    75
  30. #define DEFAULT_STEMWIDTH_SEMI    105
  31. #define DEFAULT_STEMWIDTH_BOLD    130
  32.  
  33. /* PDF's base 14 fonts, guaranteed to be always available */
  34. const char *pdf_base14fonts[] = {
  35.   "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique",
  36.   "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique",
  37.   "Symbol",
  38.   "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic",
  39.   "ZapfDingbats",
  40.   NULL
  41. };
  42.  
  43. const char *pdf_encoding_names[encoding_count] = {
  44.     NULL, "PDFDocEncoding", "MacRomanEncoding", 
  45.     "MacExpertEncoding", "WinAnsiEncoding"
  46. };
  47.  
  48. PDF_encodingvector *pdf_encoding[encoding_count] = {
  49.     NULL, &pdf_pdfdoc, &pdf_macroman, NULL, &pdf_winansi
  50. };
  51.  
  52. /* Type 1 font portions: ASCII, encrypted, zeros */
  53. typedef enum { ascii, encrypted, zeros } pdf_t1portion;
  54.  
  55. typedef struct {
  56.     pdf_t1portion portion;
  57.     long length1, length2, length3;
  58.     FILE *fontfile;
  59. } t1_private_data;
  60.  
  61. static void
  62. t1data_init(PDF *p, PDF_data_source *src)
  63. {
  64.     t1_private_data *t1_private;
  65.  
  66.     t1_private = (t1_private_data *) src->private_data;
  67.  
  68.     t1_private->portion = ascii;
  69.     t1_private->length1 = 0;
  70.     t1_private->length2 = 0;
  71.     t1_private->length3 = 0;
  72.  
  73.     src->buffer_start = (byte *) PDF_malloc(LINEBUFLEN, "t1data_init");
  74.     src->buffer_length = LINEBUFLEN;
  75. }
  76.  
  77. static bool
  78. t1data_fill(PDF *p, PDF_data_source *src)
  79. {
  80.     static const char HexToBin[] = {
  81.     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0,
  82.     10, 11, 12, 13, 14, 15 }; 
  83.     char *s, *c;
  84.     int i;
  85.     t1_private_data *t1_private;
  86.  
  87.     t1_private = (t1_private_data *) src->private_data;
  88.  
  89.     if ((s = fgets((char *) src->buffer_start, LINEBUFLEN, 
  90.         t1_private->fontfile))== NULL)
  91.     return false;
  92.  
  93.     /* check for line of zeros: set zero flag if found */
  94.     for (c = s; *c == '0'; c++)
  95.     ;
  96.     if (*c == '\n')
  97.     t1_private->portion = zeros;
  98.  
  99.     src->next_byte = src->buffer_start;
  100.  
  101.     switch (t1_private->portion) {
  102.     case ascii:
  103.         t1_private->length1 += strlen(s);
  104.         src->bytes_available = strlen(s);
  105.         break;
  106.  
  107.     case encrypted:
  108.         t1_private->length2 += strlen(s)/2;    /* ASCII -> binary */
  109.         src->bytes_available = strlen(s)/2;
  110.  
  111.         /* convert ASCII to binary in-place */
  112.         for (i=0; s[i] != '\n'; i += 2)
  113.         {
  114.         if (s[i] < '0' || s[i] > 'F' || s[i+1] < '0' || s[i+1] > 'F')
  115.             pdf_error(p, PDF_WARN, 
  116.             "Bogus Type 1 font ASCII data (%c, %c)", s[i], s[i+1]);
  117.         s[i/2] = 16*HexToBin[s[i] - '0'] + HexToBin[s[i+1] - '0'];
  118.         }
  119.         break;
  120.  
  121.     case zeros:
  122.         t1_private->length3 += strlen(s);
  123.         src->bytes_available = strlen(s);
  124.         break;
  125.     }
  126.  
  127.     if (t1_private->portion != encrypted &&
  128.         !strncmp((const char *)s, "currentfile eexec", 17))
  129.     t1_private->portion = encrypted;
  130.  
  131.     return true;
  132. }
  133.  
  134. static void
  135. t1data_terminate(PDF *p, PDF_data_source *src)
  136. {
  137.     PDF_free((void *) src->buffer_start);
  138. }
  139.  
  140. float
  141. PDF_stringwidth(PDF *p, byte *text)
  142. {
  143.     byte *cp;
  144.     float width = 0.0;
  145.  
  146.     for (cp = text; *cp; cp++)
  147.     width += p->current_font->size * p->current_font->FontWidths[*cp]/1000;
  148.  
  149.     return width;
  150. }
  151.  
  152. bool
  153. pdf_read_afm(PDF *p, char *fontname, PDF_encoding enc)
  154. {
  155.     FILE    *afmfile;
  156.     int        *widths;
  157.     FontInfo    *fi;
  158.     int        i, j;
  159.     char    filename[MAXFILENAME], *charname;
  160.     CharMetricInfo *cmi;
  161.  
  162.     /* HACK */
  163.     widths = p->current_font->FontWidths;
  164.  
  165.     /* check for afm file */
  166.     sprintf(filename, "%s.afm", fontname);
  167.  
  168.     /* try current directory */
  169.     afmfile = fopen(filename, "r");
  170.  
  171.     if (afmfile == NULL && p->info->fontpath) {
  172.     /* try font path if caller supplied one */
  173.     sprintf(filename, "%s%s%s.afm", p->info->fontpath, PATHSEP, fontname);
  174.     afmfile = fopen(filename, "r");
  175.     }
  176.     if (afmfile == NULL) {
  177.     pdf_error(p, PDF_WARN, "Couldn't open AFM file for font %s", fontname);
  178.     return false;
  179.     }
  180.  
  181.     /* parse AFM file */
  182.     if (pdf_parseFile(afmfile, &fi, P_G | P_M) != ok) {
  183.     fclose(afmfile);
  184.     pdf_error(p, PDF_FATAL, "Error parsing AFM file %s", filename);
  185.     return false;
  186.     }
  187.  
  188.     fclose(afmfile);
  189.  
  190.     if (fi->cmi == NULL) {
  191.     pdf_error(p, PDF_FATAL, 
  192.         "Couldn't parse char metrics in AFM file %s", filename);
  193.     return false;
  194.     }
  195.     /* 
  196.      * Generate character width array according to chosen encoding vector
  197.      * or the font's default encoding vector.
  198.      */
  199.     if (enc != builtin && 
  200.         strcmp(fi->gfi->encodingScheme, "AdobeStandardEncoding")) {
  201.     pdf_error(p, PDF_WARN, 
  202.         "Symbol font %s doesn't use builtin encoding", fontname);
  203.     }
  204.     if (enc == builtin &&
  205.         !strcmp(fi->gfi->encodingScheme, "AdobeStandardEncoding")) {
  206.     pdf_error(p, PDF_WARN, "Text font %s uses builtin encoding",
  207.             fontname);
  208.     enc = builtin;
  209.     }
  210.  
  211.     if (enc != builtin && pdf_encoding[enc]) {
  212.     for (i = 0; i < 256; i++) {    /* text font */
  213.         charname = (*pdf_encoding[enc])[i];
  214.         widths[i] = 0;
  215.         if (charname == NULL)    /* unencoded character */
  216.         continue;
  217.         for (j = 0, cmi = fi->cmi; j < fi->numOfChars; ++j, ++cmi) {
  218.         if (!strcmp(cmi->name, charname)) {
  219.             widths[i] = cmi->wx;
  220.             break;
  221.         }
  222.         }
  223.     }
  224.     } else {                /* symbol or pi font */
  225.     for (i = 0; i < 256; i++)
  226.         widths[i] = 0;
  227.     for (i = 0, cmi = fi->cmi; i < fi->numOfChars; i++, cmi++) {
  228.         if (cmi->code >= 0 && cmi->code < 256)
  229.         widths[cmi->code] = cmi->wx;
  230.     }
  231.     }
  232.  
  233.     /* HACK */
  234.     /* copy relevant data to current_font struct */
  235.     p->current_font->ascender        = fi->gfi->ascender;
  236.     p->current_font->descender        = fi->gfi->descender;
  237.     p->current_font->capHeight        = fi->gfi->capHeight;
  238.     p->current_font->isFixedPitch    = fi->gfi->isFixedPitch;
  239.     p->current_font->italicAngle    = fi->gfi->italicAngle;
  240.     p->current_font->llx        = fi->gfi->fontBBox.llx;
  241.     p->current_font->lly        = fi->gfi->fontBBox.lly;
  242.     p->current_font->urx        = fi->gfi->fontBBox.urx;
  243.     p->current_font->ury        = fi->gfi->fontBBox.ury;
  244.     p->current_font->StdVW        = fi->gfi->StdVW;
  245.     p->current_font->StdHW        = fi->gfi->StdHW;
  246.     p->current_font->underlinePosition    = fi->gfi->underlinePosition;
  247.     p->current_font->underlineThickness    = fi->gfi->underlineThickness;
  248.  
  249.     strcpy(p->current_font->fontName,      fi->gfi->fontName);
  250.     strcpy(p->current_font->encodingScheme,  fi->gfi->encodingScheme);
  251.     strcpy(p->current_font->weight,      fi->gfi->weight);
  252.  
  253.     /* 
  254.      * If we don't know the exact stem width we use default values
  255.      * according to the font weight (regular, semi, or bold)
  256.      */
  257.     if (p->current_font->StdVW == 0) {
  258.     if (!strcmp(p->current_font->weight, "Semibold"))
  259.         p->current_font->StdVW = DEFAULT_STEMWIDTH_SEMI;
  260.     else if (!strcmp(p->current_font->weight, "Bold"))
  261.         p->current_font->StdVW = DEFAULT_STEMWIDTH_BOLD;
  262.     else
  263.         p->current_font->StdVW = DEFAULT_STEMWIDTH;
  264.     }
  265.  
  266.     /* free AFM parser's storage */
  267.     freeStorage(fi);
  268.  
  269.     return true;
  270. }
  271.  
  272. void
  273. pdf_put_t1font(PDF *p, char *fontname, id font_id, int fontnumber, bool embed)
  274. {
  275.     FILE    *fontfile = NULL;
  276.     char    filename[MAXFILENAME];
  277.     int        *widths;
  278.     int        i, j;
  279.     unsigned long    fontflags;
  280.     id        fontdescriptor_id, fontfile_id = 0l;
  281.     id        length_id, length1_id, length2_id, length3_id;
  282.     long    length, stream_start;
  283.     PDF_data_source t1src;
  284.     const char    **cp;
  285.     PDF_encoding enc;
  286.  
  287.     enc        = p->current_font->encoding;
  288.  
  289.     /* Should use font cache instead */
  290.     if (!pdf_read_afm(p, fontname, enc)) {    /* HACK */
  291.     pdf_error(p, PDF_FATAL, "Couldn't read metrics for font %s", fontname);
  292.     return;
  293.     }
  294.  
  295.     widths    = p->current_font->FontWidths;
  296.  
  297.     /* check whether we have one of the base 14 fonts */
  298.     for (cp = pdf_base14fonts; *cp; ++cp)
  299.     if (!strcmp(*cp, fontname)) {
  300.         pdf_begin_obj(p, font_id);
  301.         pdf_begin_dict(p);
  302.  
  303.         (void) fputs("/Type /Font\n", p->fp);
  304.         (void) fputs("/Subtype /Type1\n", p->fp);
  305.         (void) fprintf(p->fp, "/Name /F%d\n", fontnumber);
  306.  
  307.         if (enc != builtin) {
  308.         (void) fprintf(p->fp, "/Encoding /%s\n", 
  309.                 pdf_encoding_names[enc]);
  310.         }
  311.         (void) fprintf(p->fp, "/BaseFont /%s\n", *cp);
  312.  
  313.         pdf_end_dict(p);
  314.         pdf_end_obj(p);        /* font */
  315.  
  316.         return;
  317.     }
  318.  
  319.     /* check for font file */
  320.     strcpy(filename, fontname);
  321.     if (embed) {
  322.     /* try current directory */
  323.     fontfile = fopen(filename, "r");
  324.  
  325.     if (fontfile == NULL && p->info->fontpath) {
  326.         /* try font path if caller supplied one */
  327.         sprintf(filename, "%s%s%s", p->info->fontpath, PATHSEP, fontname);
  328.         fontfile = fopen(filename, "r");
  329.     }
  330.     if (fontfile == NULL) {
  331.         pdf_error(p, PDF_WARN, "Couldn't open font file %s", filename);
  332.         embed = false;
  333.     }
  334.     }
  335.  
  336.     /* Section 7.5: Font attributes */
  337.     pdf_begin_obj(p, font_id);
  338.     pdf_begin_dict(p);
  339.     (void) fputs("/Type /Font\n", p->fp);
  340.     (void) fputs("/Subtype /Type1\n", p->fp);
  341.     (void) fprintf(p->fp, "/Name /F%d\n", fontnumber);
  342.     (void) fputs("/FirstChar 0\n", p->fp);
  343.     (void) fputs("/LastChar 255\n", p->fp);
  344.  
  345.     (void) fputs("/Widths [\n", p->fp);
  346.  
  347.     for (i = 0; i < 16; i++) {
  348.     for (j = 0; j < 16; j++)
  349.         (void) fprintf(p->fp, " %d", widths[16*i + j]);
  350.     (void) fputs("\n", p->fp);
  351.     }
  352.  
  353.     (void) fputs("]\n", p->fp);
  354.  
  355.     if (enc != builtin) {
  356.     (void) fprintf(p->fp, "/Encoding /%s\n", 
  357.             pdf_encoding_names[enc]);
  358.     }
  359.     (void) fprintf(p->fp, "/BaseFont /%s\n", fontname);
  360.  
  361.     fontdescriptor_id = pdf_alloc_id(p);
  362.     (void) fprintf(p->fp, "/FontDescriptor %ld 0 R\n", fontdescriptor_id);
  363.  
  364.     pdf_end_dict(p);
  365.     pdf_end_obj(p);        /* font */
  366.  
  367.     /* Section 7.8: font descriptors */
  368.     pdf_begin_obj(p, fontdescriptor_id);
  369.     pdf_begin_dict(p);
  370.     (void) fputs( "/Type /FontDescriptor\n", p->fp);
  371.     (void) fprintf(p->fp, "/Ascent %d\n", p->current_font->ascender);
  372.     (void) fprintf(p->fp, "/CapHeight %d\n", p->current_font->capHeight);
  373.     (void) fprintf(p->fp, "/Descent %d\n", p->current_font->descender);
  374.  
  375.     fontflags = 0;
  376.     if (p->current_font->isFixedPitch)
  377.         fontflags |= FIXEDWIDTH;
  378.  
  379.     if (!strcmp(p->current_font->encodingScheme, "AdobeStandardEncoding"))
  380.         fontflags |= ADOBESTANDARD;
  381.     else
  382.         fontflags |= SYMBOL;
  383.  
  384.     if (p->current_font->italicAngle < 0)
  385.         fontflags |= ITALIC;
  386.  
  387.     /* heuristic to identify (small) caps fonts */
  388.     if (strstr(fontname, "Caps") ||
  389.     !strcmp(fontname + strlen(fontname) - 2, "SC"))
  390.         fontflags |= SMALLCAPS;
  391.  
  392.     /* this doesn't catch all cases but will do for the moment */
  393.     if (!strcmp(p->current_font->weight, "Bold"))
  394.         fontflags |= FORCEBOLD;
  395.  
  396.     (void) fprintf(p->fp, "/Flags %ld\n", fontflags);
  397.  
  398.     (void) fprintf(p->fp, "/FontBBox [%d %d %d %d ]\n",
  399.             p->current_font->llx,  p->current_font->lly,
  400.             p->current_font->urx,  p->current_font->ury);
  401.  
  402.     (void) fprintf(p->fp, "/FontName /%s\n", fontname);
  403.     (void) fprintf(p->fp, "/ItalicAngle %d\n", 
  404.             (int) (p->current_font->italicAngle));
  405.  
  406.     (void) fprintf(p->fp, "/StemV %d\n", p->current_font->StdVW);
  407.  
  408.     if (embed) {
  409.     fontfile_id = pdf_alloc_id(p);
  410.     (void) fprintf(p->fp, "/FontFile %ld 0 R\n", fontfile_id);
  411.     }
  412.  
  413.     pdf_end_dict(p);
  414.     pdf_end_obj(p);        /* font descriptor */
  415.  
  416.     /* Section 7.8.1: font files */
  417.     if (embed) {
  418.     pdf_begin_obj(p, fontfile_id);
  419.     pdf_begin_dict(p);
  420.     if (p->info->binary_mode == false)
  421.         (void) fputs("/Filter /ASCIIHexDecode\n", p->fp);
  422.  
  423.     length_id = pdf_alloc_id(p);
  424.     length1_id = pdf_alloc_id(p);
  425.     length2_id = pdf_alloc_id(p);
  426.     length3_id = pdf_alloc_id(p);
  427.     (void) fprintf(p->fp, "/Length %ld 0 R\n", length_id);
  428.     (void) fprintf(p->fp, "/Length1 %ld 0 R\n", length1_id);
  429.     (void) fprintf(p->fp, "/Length2 %ld 0 R\n", length2_id);
  430.     (void) fprintf(p->fp, "/Length3 %ld 0 R\n", length3_id);
  431.  
  432.     /* Don't omit zeros since more data may follow at the end! */
  433.     pdf_end_dict(p);
  434.  
  435.     pdf_begin_stream(p);            /* font data stream */
  436.     stream_start = ftell(p->fp);
  437.  
  438.     t1src.init        = t1data_init;
  439.     t1src.fill        = t1data_fill;
  440.     t1src.terminate        = t1data_terminate;
  441.  
  442.     t1src.private_data = (unsigned char *)
  443.             PDF_malloc(sizeof(t1_private_data), "pdf_put_t1font");
  444.     ((t1_private_data *) t1src.private_data)->fontfile = fontfile;
  445.  
  446.     if (p->info->binary_mode) {
  447.         t1src.init(p, &t1src);
  448.  
  449.         while (t1src.fill(p, &t1src))
  450.         (void) fwrite(t1src.next_byte, 1, t1src.bytes_available, p->fp);
  451.  
  452.         t1src.terminate(p, &t1src);
  453.     } else
  454.         pdf_ASCIIHexEncode(p, &t1src);
  455.  
  456.     length = ftell(p->fp) - stream_start;
  457.     pdf_end_stream(p);
  458.     pdf_end_obj(p);                /* font file object */
  459.  
  460.     pdf_begin_obj(p, length_id);        /* Length object */
  461.     (void) fprintf(p->fp,"%ld\n", length);
  462.     pdf_end_obj(p);
  463.  
  464.     pdf_begin_obj(p, length1_id);        /* Length1 object */
  465.     (void) fprintf(p->fp,"%ld\n", 
  466.         ((t1_private_data *) t1src.private_data)->length1);
  467.     pdf_end_obj(p);
  468.  
  469.     pdf_begin_obj(p, length2_id);        /* Length2 object */
  470.     (void) fprintf(p->fp,"%ld\n",
  471.         ((t1_private_data *) t1src.private_data)->length2);
  472.     pdf_end_obj(p);
  473.  
  474.     pdf_begin_obj(p, length3_id);        /* Length3 object */
  475.     (void) fprintf(p->fp,"%ld\n",
  476.         ((t1_private_data *) t1src.private_data)->length3);
  477.     pdf_end_obj(p);
  478.  
  479.     fclose(((t1_private_data *) t1src.private_data)->fontfile);
  480.     PDF_free((void *) t1src.private_data);
  481.     }
  482. }
  483.